package com.jse.jdbc;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import javax.sql.DataSource;

import com.jse.Compiler;
import com.jse.Refs;

/**
 * 
 */
public class JseDataSource implements DataSource{
 
	final static CopyOnWriteArrayList<JseConnection> pool = new CopyOnWriteArrayList<>();
    private ScheduledExecutorService scheduled=Executors.newSingleThreadScheduledExecutor();
	private String name;
	private String url;//jdbc url
	private String user;
	private String password;
	private int initialPoolSize;//初始化大小 5
	private int idleTimeout;//连接允许被闲置在池中的最大时间 600000 5分钟
	private long maxLifetime;//控制池中连接的最大生命周期 默认值为1800000（30分钟）
//	private int maximumPoolSize;//参数作用：控制数据库连接池连接数允许到达的最大值，包括空闲和正在使用的连接 50
	private int minimumldle;//尝试在池中维护的最小空闲连接数 5
    
    public JseDataSource(Map<String,Object> prop) {
    	url=(String)prop.get("url");
    	user=(String)prop.get("username");
    	password=(String)prop.get("password");
    	initialPoolSize=Integer.valueOf(prop.getOrDefault("initialPoolSize",5).toString());
    	idleTimeout=Integer.valueOf(prop.getOrDefault("idleTimeout",600000).toString());
    	maxLifetime=Long.valueOf(prop.getOrDefault("maxLifetime",1800000).toString());
    	if(maxLifetime<600000)maxLifetime=600000;//配置最大生命周期(检查)不能小于5分钟
//    	maximumPoolSize=Integer.valueOf(prop.getOrDefault("maximumPoolSize",50).toString());
    	minimumldle=Integer.valueOf(prop.getOrDefault("minimumldle",5).toString());
    	try {
    		for (int i = 0; i < initialPoolSize; i++) {
        		Connection conn = DriverManager.getConnection(url,user, password);
        		pool.add(new JseConnection(conn));
    		}
		} catch (SQLException e) {
			e.printStackTrace();
		}
    	scheduled.scheduleAtFixedRate(this::check,0,maxLifetime,TimeUnit.MILLISECONDS);//30分钟检查
    }
    
    private void check() {
    	long time=System.currentTimeMillis();
    	try {
    		for (JseConnection c : pool) {
        		if(!c.use){//已使用跳过
        			if((time-c.createtime)>idleTimeout) {//超过允许闲置的最大时间
        				c.destroy(); //关闭
        				pool.remove(c);//从池中删除
        			}
        		}
			}
    		for (int i = pool.size();i<minimumldle; i++) {
        		pool.add(new JseConnection(DriverManager.getConnection(url,user, password)));
    		}
    		Jdbc.log.trace("触发检查 当前连接:%d",pool.size());
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
    
	@Override
	public Connection getConnection() throws SQLException {
		if(pool.size()>0){
			final JseConnection conn = pool.removeFirst();
			conn.use=true;//标记为使用
			if(pool.size()<minimumldle){//小于最小空闲连接
        		pool.add(new JseConnection(DriverManager.getConnection(url,user, password)));
			}
			Jdbc.log.trace("获取连接 当前连接数:%d",pool.size());
			return conn;
		}else throw new RuntimeException("连接池内没有连接请检查!");
		
	}
	
	
	
	@Override
	public PrintWriter getLogWriter() throws SQLException {
		return null;
	}
 
	@Override
	public void setLogWriter(PrintWriter out) throws SQLException {
		// TODO Auto-generated method stub
		
	}
 
	@Override
	public void setLoginTimeout(int seconds) throws SQLException {
		// TODO Auto-generated method stub
		
	}
 
	@Override
	public int getLoginTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return 0;
	}
 
	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		return null;
	}
 
	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}
 
	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}
 
 
	@Override
	public Connection getConnection(String username, String password)
			throws SQLException {
		return DriverManager.getConnection(url,username,password);
	}
	
}